package com.ham.ui;

import java.awt.Dimension;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.swing.JPanel;

import org.javabuilders.BuildResult;
import org.javabuilders.swing.SwingJavaBuilder;

/**
 * 
 * @author fredy
 * 
 */
public abstract class ManagedPanel extends JPanel {
	public static final String EVENT_PANEL_INITIALIZED = "initialized";

	/**
	 * 
	 */
	private static final long serialVersionUID = 4422725516934183438L;
	// private Container<?> wrapper;
	private BuildResult buildResult;
	private String title;
	private boolean initialized;
	private Map<String, String> menuParams;
	private Object preInitResult;
	private List<Field> injectedPanelFields = new ArrayList<Field>();

	/**
	 * Akan dieksekusi dalam EDT, dengan demikian semua inisialisasi Swing
	 * Component harus dilakukan dalam method ini
	 */
	protected abstract void initComponents(Map<String, String> args);

	/**
	 * Dieksekusi dalam worker thread untuk menghindari blocking UI/unresponsive
	 * UI
	 * 
	 * @param args
	 *            menu parameter
	 */
	protected Object preInitialization(Map<String, String> args) {
		return null;
	}

	/**
	 * Akan dieksekusi dalam EDT, component yang membutuhkan hasil proses
	 * preInitialization dapat melakukannya di sini
	 * 
	 * @param args
	 *            menu parameter
	 * @param preInitializationResult
	 *            return value dari preInitialization
	 */
	protected void postInitialization(Map<String, String> args,
			Object preInitializationResult) {
	}

	// protected ManagedPanel[] getComponentPanels() {
	// return new ManagedPanel[] {};
	// }

	void postInitialize() throws Exception {
		initComponents(menuParams);
		postInitialization(menuParams, preInitResult);
		setInitialized(true);
		for (Field field : injectedPanelFields) {
			boolean accessible = field.isAccessible();
			field.setAccessible(true);
			ManagedPanel p = (ManagedPanel) field.get(this);
			p.postInitialize();
			field.setAccessible(accessible);
		}
		// Field[] declaredFields = getClass().getDeclaredFields();
		// for (Field field : declaredFields) {
		// if (ManagedPanel.class.isAssignableFrom(field.getType())) {
		// boolean accessible = field.isAccessible();
		// field.setAccessible(true);
		// ManagedPanel p = (ManagedPanel) field.get(this);
		// p.postInitialize();
		// field.setAccessible(accessible);
		// }
		// }
	}

	Object initialize() throws Exception {
		if (initialized) {
			return null;
		}
		// Object result = preInitialization(menuParams);
		preInitResult = preInitialization(menuParams);
		setBuildResult(SwingJavaBuilder.build(this));
		for (Field field : injectedPanelFields) {
			boolean accessible = field.isAccessible();
			field.setAccessible(true);
			((ManagedPanel) field.get(this)).initialize();
			field.setAccessible(accessible);
		}

		// Field[] declaredFields = getClass().getDeclaredFields();
		// for (Field field : declaredFields) {
		// if (ManagedPanel.class.isAssignableFrom(field.getType())) {
		// boolean accessible = field.isAccessible();
		// field.setAccessible(true);
		// ((ManagedPanel) field.get(this)).initialize();
		// field.setAccessible(accessible);
		// }
		// }

		return preInitResult;

		// final ManagedPanel panel = this;
		// UIUtils.executeWorker(new SwingWorker<Object, Void>() {
		//
		// @Override
		// protected Object doInBackground() throws Exception {
		//
		// Object result = preInitialization(panel.menuParams);
		// System.out.println(panel.getClass().getName());
		// setBuildResult(SwingJavaBuilder.build(panel));
		//
		// Field[] declaredFields = panel.getClass().getDeclaredFields();
		// for (Field field : declaredFields) {
		// if (ManagedPanel.class.isAssignableFrom(field.getType())) {
		// boolean accessible = field.isAccessible();
		// field.setAccessible(true);
		// ((ManagedPanel) field.get(panel)).initialize();
		// field.setAccessible(accessible);
		// }
		// }
		//
		// return result;
		// }
		//
		// @Override
		// protected void done() {
		// try {
		// initComponents(panel.menuParams);
		// postInitialization(panel.menuParams, get());
		//
		// setInitialized(true);
		// } catch (Exception e) {
		// throw new AppRuntimeException(e,
		// ErrorCodeCatalog.GENERAL_ERROR);
		// }
		// }
		// });
	}

	public Dimension getDefaultSize() {
		Dimension size = getSize();
		Dimension defaultSize = (null != size && !(size.getHeight() == 0d || size
				.equals(new Dimension(1, 1)))) ? size : new Dimension(700, 525);
		return defaultSize;
	}

	public String getTitle() {
		return title;
	}

	// public Container<?> getWrapper() {
	// return wrapper;
	// }
	//
	// public void setWrapper(Container<?> wrapper) {
	// this.wrapper = wrapper;
	// }

	public BuildResult getBuildResult() {
		return buildResult;
	}

	public void setBuildResult(BuildResult buildResult) {
		this.buildResult = buildResult;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public boolean isInitialized() {
		return initialized;
	}

	public void setInitialized(boolean initialized) {
		boolean old = this.initialized;
		this.initialized = initialized;
		firePropertyChange(EVENT_PANEL_INITIALIZED, old, initialized);
	}

	public Map<String, String> getMenuParams() {
		return menuParams;
	}

	void setMenuParams(Map<String, String> menuParams) {
		this.menuParams = menuParams;
	}

	List<Field> getInjectedPanelFields() {
		return injectedPanelFields;
	}

}
